package com.zdp.netty.chapter14.codec;

import com.zdp.netty.chapter14.struct.NettyMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import jdk.nashorn.internal.ir.CallNode;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * NettyMessage消息编码器，编码规则：
 * 1. crcCode： java.nio.ByteBuffer.putInt(int value)
 * 2. length: java.nio.ByteBuffer.putInt(int value)
 * 3. sessionId: java.nio.ByteBuffer.putLong(long value)
 * 4. type： java.nio.ByteBuffer.put(byte value)
 * 5. priority: java.nio.ByteBuffer.put(byte value)
 * 6. attachment: 如果attachment长度为0，表示没有可选附件，则将长度编码设为0，java.nio.ByteBuffer.putInt(0)；
 *                如果大于0，说明有附件需要编码,具体规则如下：
 *    6.1. 对附件数量进行编码： java.nio.ByteBuffer.putInt(attachment.size();)
 *    6.2 对Key、Value进行编码，先编码Key，再编码Value(先记录Key长度)
 *          buffer.writeString(Key)
 *          buffer.writeBinary(value)
 * 7. Body: 通过JBoss Marshalling将其序列化为byte数组，
 *          然后调用java.nio.ByteBuffer.put(byte [] src)将其写入ByteBuffer缓冲区中
 * 最后更新 length
 * @author ZhengDp
 * @Date 2024/4/10 8:37
 */
public class NettyMessageEncoder extends MessageToByteEncoder<NettyMessage> {

    MarshallingEncoder marshallingEncoder;

    public NettyMessageEncoder() throws IOException {
        this.marshallingEncoder  = new MarshallingEncoder();
    }

    @Override
    protected void encode(ChannelHandlerContext ctx, NettyMessage msg, ByteBuf sendBuf) throws Exception {
        if(Objects.isNull(msg) || Objects.isNull(msg.getHeader())) {
            throw new Exception("The encode message is null");
        }
        // 先编码请求头
        sendBuf.writeInt(msg.getHeader().getCrcCode());
        sendBuf.writeInt(msg.getHeader().getLength());
        sendBuf.writeLong(msg.getHeader().getSessionId());
        sendBuf.writeByte(msg.getHeader().getType());
        sendBuf.writeByte(msg.getHeader().getPriority());
        // 附件处理
        sendBuf.writeInt(msg.getHeader().getAttachment().size());
        byte[] keyArray = null;
        for(Map.Entry<String,Object> param : msg.getHeader().getAttachment().entrySet()) {
            String key = param.getKey();
            keyArray = key.getBytes(StandardCharsets.UTF_8);
            sendBuf.writeInt(keyArray.length);
            sendBuf.writeBytes(keyArray);
            Object value = param.getValue();
            marshallingEncoder.encode(value,sendBuf);
        }
        keyArray = null;
        if(Objects.nonNull(msg.getBody())) {
            marshallingEncoder.encode(msg.getBody(),sendBuf);
        } else {
            sendBuf.writeInt(0);
        }
        sendBuf.setInt(4,sendBuf.readableBytes() - 8);
    }


}
